package com.ys.gulimall.order.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ys.common.utils.R;
import com.ys.common.vo.MemberResponseVo;
import com.ys.gulimall.order.constant.OrderConstant;
import com.ys.gulimall.order.constant.OrderStatusEnum;
import com.ys.gulimall.order.entity.OrderItemEntity;
import com.ys.gulimall.order.feign.CartFeignService;
import com.ys.gulimall.order.feign.MemberFeignService;
import com.ys.gulimall.order.feign.ProductFeignService;
import com.ys.gulimall.order.feign.WmsFeignService;
import com.ys.gulimall.order.interceptor.LoginUserInterceptor;
import com.ys.gulimall.order.service.OrderItemService;
import com.ys.gulimall.order.vo.*;
import org.springframework.data.redis.core.ReactiveRedisOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ys.common.utils.PageUtils;
import com.ys.common.utils.Query;

import com.ys.gulimall.order.dao.OrderDao;
import com.ys.gulimall.order.entity.OrderEntity;
import com.ys.gulimall.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.annotation.Resource;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {
	
	private ThreadLocal<OrderSubmitVo> confirmVoThreadLocal = new ThreadLocal<>();
	
	@Resource
	private MemberFeignService memberFeignService;
	
	@Resource
	private CartFeignService cartFeignService;
	
	@Resource
	private ThreadPoolExecutor executor;
	
	@Resource
	private WmsFeignService wmsFeignService;
	
	@Resource
	private StringRedisTemplate stringRedisTemplate;
	
	@Resource
	private ProductFeignService productFeignService;
	
	@Resource
	private OrderItemService orderItemService;
	
	@Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }
	
	@Override
	public OrderConfirmVo confirmOrder() throws ExecutionException, InterruptedException {
		OrderConfirmVo confirmVo = new OrderConfirmVo();
		MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
		
		//feign在远程调用之前要构造请求，调用很多拦截器RequestInterceptor interceptor: requestInterceptors
		
		RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
		
		CompletableFuture<Void> getAddressFuture = CompletableFuture.runAsync(() -> {
			//每一个线程都来共享之前的请求数据
			RequestContextHolder.setRequestAttributes(requestAttributes);
			//1、远程查询所有的收货地址列表
			List<MemberAddressVo> address = memberFeignService.getAddress(memberResponseVo.getId());
			confirmVo.setAddress(address);
		}, executor);
		
		CompletableFuture<Void> cartFuture = CompletableFuture.runAsync(() -> {
			RequestContextHolder.setRequestAttributes(requestAttributes);
			//2、远程查询购物车所有选中的购物项
			List<OrderItemVo> items = cartFeignService.getCurrentUserCartItems();
			confirmVo.setItems(items);
		}, executor).thenRunAsync(()->{
			//查询库存信息
			List<OrderItemVo> items = confirmVo.getItems();
			List<Long> collect = items.stream().map(item -> item.getSkuId()).collect(Collectors.toList());
			
			R hasStock = wmsFeignService.getSkusHasStock(collect);
			List<SkuStockVo> data = hasStock.getData(new TypeReference<List<SkuStockVo>>() {
			});
			if (data != null){
				Map<Long, Boolean> map = data.stream().collect(Collectors.toMap(SkuStockVo::getSkuId, SkuStockVo::getHasStock));
				confirmVo.setStocks(map);
			}
			
		},executor);
		
		//3、查询用户积分
		Integer integration = memberResponseVo.getIntegration();
		confirmVo.setIntegration(integration);
		
		//4、其他数据自动计算
		
		//5、TODO 防重令牌 接口幂等性
		String token = UUID.randomUUID().toString().replace("-", "");
		stringRedisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResponseVo.getId(),token,30, TimeUnit.MINUTES);
		confirmVo.setOrderToken(token);
		
		
		CompletableFuture.allOf(getAddressFuture, cartFuture).get();
		return confirmVo;
	}
	
	@Transactional
	@Override
	public SubmitOrderResponseVo submitOrder(OrderSubmitVo submitVo) {
		confirmVoThreadLocal.set(submitVo);
		SubmitOrderResponseVo response = new SubmitOrderResponseVo();
		MemberResponseVo memberResponseVO = LoginUserInterceptor.loginUser.get();
		response.setCode(0);
		// 1、验证令牌【令牌的对比和删除必须保证原子性】
		// 0令牌失败 1删除成功
		String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
		String orderToken = submitVo.getOrderToken();
		// 原子验证令牌和删除令牌
		Long result = stringRedisTemplate.execute(new DefaultRedisScript<>(script, Long.class), Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + memberResponseVO.getId()), orderToken);
		if (result == 0L) {
			// 令牌验证失败
			response.setCode(1);
			return response;
		} else {
			// 令牌验证成功 下单 去创建订单 验证令牌 核算价格 锁定库存
			// 1、创建订单，订单项等信息
			OrderCreateTo order = createOrder();
			// 2、验价
			BigDecimal payAmount = order.getOrder().getPayAmount();
			BigDecimal payPrice = submitVo.getPayPrice();
			if (Math.abs(payAmount.subtract(payPrice).doubleValue()) <0.01){
				// 金额对比成功
				// 3、保持订单
				saveOrder(order);
				// 4、库存锁定,只要有异常回滚订单数据。订单号，订单项信息（skuId,skuName,num）
				//WareSkuLockVo wareSkuLockVo = new WareSkuLockVo();
				//wareSkuLockVo.setOrderSn(order.getOrder().getOrderSn());
				//List<OrderItemVo> orderItemVos = order.getOrderItems().stream().map(item -> {
				//	OrderItemVo orderItemVo = new OrderItemVo();
				//	orderItemVo.setSkuId(item.getSkuId());
				//	orderItemVo.setCount(item.getSkuQuantity());
				//	orderItemVo.setTitle(item.getSkuName());
				//	return orderItemVo;
				//}).collect(Collectors.toList());
				//wareSkuLockVo.setLocks(orderItemVos);
				//// TODO 远程锁库存
				//R r = wmsFeignService.orderLockStock(wareSkuLockVo);
				//if (r.getCode() == 0){
				//	//锁成功了
					response.setOrder(order.getOrder());
					return response;
				//}else {
				//	//锁定失败
				//	throw new NoStockException((String) r.get("msg"));
				//}
			}else {
				response.setCode(2);
				return response;
			}
		}
	}
	
	/**
	 * 生成一个订单
	 * @return
	 */
	public OrderCreateTo createOrder(){
		OrderCreateTo createTo = new OrderCreateTo();
		// 1、生成一个订单号
		String orderSn = IdWorker.getTimeId();
		// 创建订单
		OrderEntity orderEntity = buildOrder(orderSn);
		createTo.setOrder(orderEntity);
		// 2、获取所有的订单项
		List<OrderItemEntity> itemEntities = buildOrderItems(orderSn);
		createTo.setOrderItems(itemEntities);
		// 3、计算价格、积分等相关
		computePrice(orderEntity,itemEntities);
		return createTo;
	}
	
	/**
	 * 创建订单
	 * @param orderSn
	 * @return
	 */
	private OrderEntity buildOrder(String orderSn) {
		MemberResponseVo memberResponseVo = LoginUserInterceptor.loginUser.get();
		OrderEntity orderEntity = new OrderEntity();
		orderEntity.setOrderSn(orderSn);
		orderEntity.setMemberId(memberResponseVo.getId());
		OrderSubmitVo orderSubmitVo = confirmVoThreadLocal.get();
		// 获取收获地址信息
		R r = wmsFeignService.getFare(orderSubmitVo.getAddrId());
		FareVo fareResp = r.getData(new TypeReference<FareVo>() {
		});
		// 设置运费信息
		orderEntity.setFreightAmount(fareResp.getFare());
		// 设置收货人信息
		orderEntity.setReceiverCity(fareResp.getAddress().getCity());
		orderEntity.setReceiverDetailAddress(fareResp.getAddress().getDetailAddress());
		orderEntity.setReceiverName(fareResp.getAddress().getName());
		orderEntity.setReceiverPhone(fareResp.getAddress().getPhone());
		orderEntity.setReceiverPostCode(fareResp.getAddress().getPostCode());
		orderEntity.setReceiverRegion(fareResp.getAddress().getRegion());
		// 设置订单的相关状态信息
		orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
		orderEntity.setAutoConfirmDay(7);
		return orderEntity;
	}
	
	/**
	 * 构建所有订单项数据
	 * @return
	 */
	private List<OrderItemEntity> buildOrderItems(String orderSn) {
		// 最后确定每个购物项的价格
		List<OrderItemVo> currentUserCartItems = cartFeignService.getCurrentUserCartItems();
		if (currentUserCartItems != null && currentUserCartItems.size()>0){
			List<OrderItemEntity> itemEntities = currentUserCartItems.stream().map(cartItem -> {
				OrderItemEntity itemEntity = buildOrderItem(cartItem);
				itemEntity.setOrderSn(orderSn);
				return itemEntity;
			}).collect(Collectors.toList());
			return itemEntities;
		}
		return null;
	}
	
	/**
	 * 构建某一个订单项
	 * @param cartItem
	 * @return
	 */
	private OrderItemEntity buildOrderItem(OrderItemVo cartItem) {
		OrderItemEntity orderItemEntity = new OrderItemEntity();
		// 1 订单信息 订单号
		// 2 SPU信息
		Long skuId = cartItem.getSkuId();
		R r = productFeignService.getSpuInfoBySkuId(skuId);
		SpuInfoVo data = r.getData(new TypeReference<SpuInfoVo>(){});
		orderItemEntity.setSpuId(data.getId());
		orderItemEntity.setSpuBrand(data.getBrandId().toString());
		orderItemEntity.setSpuName(data.getSpuName());
		orderItemEntity.setCategoryId(data.getCatalogId());
		// 3 SKU信息
		orderItemEntity.setSkuId(cartItem.getSkuId());
		orderItemEntity.setSkuName(cartItem.getTitle());
		orderItemEntity.setSkuPic(cartItem.getDefaultImg());
		orderItemEntity.setSkuPrice(cartItem.getPrice());
		String skuAttrs = StringUtils.collectionToDelimitedString(cartItem.getSkuAttrValues(), ";"); //将集合转换成字符串
		orderItemEntity.setSkuAttrsVals(skuAttrs);
		orderItemEntity.setSkuQuantity(cartItem.getCount());
		// 4 优惠信息 [不做]
		
		// 5 积分信息
		orderItemEntity.setGiftGrowth(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount().toString())).intValue());
		orderItemEntity.setGiftIntegration(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount().toString())).intValue());
		// 6 订单项的价格信息
		orderItemEntity.setPromotionAmount(new BigDecimal("0"));
		orderItemEntity.setIntegrationAmount(new BigDecimal("0"));
		orderItemEntity.setCouponAmount(new BigDecimal("0"));
		// 当前订单项的实际金额
		BigDecimal origin = orderItemEntity.getSkuPrice().multiply(new BigDecimal(orderItemEntity.getSkuQuantity().toString()));
		// 总额减去各种优惠后的价格
		BigDecimal subtract = origin.subtract(orderItemEntity.getCouponAmount()).subtract(orderItemEntity.getIntegrationAmount()).subtract(orderItemEntity.getPromotionAmount());
		orderItemEntity.setRealAmount(subtract);
		return orderItemEntity;
	}
	
	/**
	 * 计算价格相关
	 * @param orderEntity
	 * @param itemEntities
	 */
	private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> itemEntities) {
		BigDecimal total = new BigDecimal("0.0");
		BigDecimal coupon = new BigDecimal("0.0");
		BigDecimal integration = new BigDecimal("0.0");
		BigDecimal promotion = new BigDecimal("0.0");
		BigDecimal gift = new BigDecimal("0.0");
		BigDecimal growth = new BigDecimal("0.0");
		// 订单的总额，叠加每一个订单项的总额信息。
		for (OrderItemEntity entity : itemEntities) {
			coupon = coupon.add(entity.getCouponAmount());
			integration = integration.add(entity.getIntegrationAmount());
			promotion = promotion.add(entity.getPromotionAmount());
			total = total.add(entity.getRealAmount());
			gift = gift.add(new BigDecimal(entity.getGiftIntegration().toString()));
			growth = growth.add(new BigDecimal(entity.getGiftGrowth().toString()));
		}
		// 订单价格相关
		orderEntity.setTotalAmount(total);
		// 应付金额
		orderEntity.setPayAmount(total.add(orderEntity.getFreightAmount()));
		orderEntity.setPromotionAmount(promotion);
		orderEntity.setIntegrationAmount(integration);
		orderEntity.setCouponAmount(coupon);
		// 设置积分信息
		orderEntity.setIntegration(gift.intValue());
		orderEntity.setGrowth(growth.intValue());
		// 设置删除状态 0未删除
		orderEntity.setDeleteStatus(0);
	}
	
	/**
	 * 保存订单数据
	 * @param order
	 */
	private void saveOrder(OrderCreateTo order) {
		OrderEntity orderEntity = order.getOrder();
		orderEntity.setModifyTime(new Date());
		this.save(orderEntity);
		List<OrderItemEntity> orderItems = order.getOrderItems();
		orderItemService.saveBatch(orderItems);
	}
	
}